#include <iostream>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <pthread.h>
#include "Lock.hpp"
#include <mutex> // C++11

using namespace std;

int tickets = 1000;
Mutex mymutex;

// RAII风格的加锁方式 -- 不可被重入函数
// 函数本质是一个代码块, 会被多个线程同时调用执行，该函数被重复进入 -- 被重入了
bool getTickets()
{
    static int cnt = 0; // 统计该函数被调用的次数

    bool ret = false;              // 函数的局部变量，在栈上保存，线程具有独立的栈结构，每个线程各自一份
    LockGuard lockGuard(&mymutex); // 局部对象的声明周期是随代码块的！
    
    if (tickets > 0)
    {
        usleep(1001); // 线程切换了
        cout << "thread: " << pthread_self() << " get a ticket: " << tickets << endl;
        tickets--;
        ret = true;
    }
    cnt++;

    // 当线程退出代码块时，自动调用其析构函数
    return ret;
}

void *startRoutine(void *args)
{
    const char *name = static_cast<const char *>(args);
    while (true)
    {
        if (!getTickets())
        {
            break;
        }
        cout << name << " get tickets success" << endl;

        // 其他事情要做
        usleep(100);
    }
}

int main()
{
    // malloc 底层一定要调用底层申请函数，brk
    pthread_t t1, t2, t3, t4;

    // C++11
    // std::mutex mutex_;
    // mutex_.lock();
    // mutex_.unlock();

    // 代码块:
    // {
    //     // {}内部的全部都是临界资源，自动进行加锁了
    //     LockGuard LockGuard(&mymutex);
    //     // 进入代码块时，局部变量自动调用构造函数
    //     cnt++;
    //     ...
    //     ...
    //     ...
    //     // 退出代码块时自动调用析构函数
    // }

    // lock();
    // cnt++
    // unlock();

    pthread_create(&t1, nullptr, startRoutine, (void *)"thread 1");
    pthread_create(&t2, nullptr, startRoutine, (void *)"thread 2");
    pthread_create(&t3, nullptr, startRoutine, (void *)"thread 3");
    pthread_create(&t4, nullptr, startRoutine, (void *)"thread 4");

    pthread_join(t1, nullptr);
    pthread_join(t2, nullptr);
    pthread_join(t3, nullptr);
    pthread_join(t4, nullptr);

    return 0;
}
